Hi all, is it possible to disable the "Do not show my picture" on Lync client ?
I want to stop that an user can disable photo.
Thanks a lot
Technology Tips and News
Hi all, is it possible to disable the "Do not show my picture" on Lync client ?
I want to stop that an user can disable photo.
Thanks a lot
I haven't tested this yet, but have you played with creating a CsClientPolicy and applying it to the users.
http://www.shudnow.net/2010/10/28/lync-2010-client-policies/
http://technet.microsoft.com/en-us/library/gg398300.aspx
The DisplayPhoto attribute has a number of options:
Determines whether or not photos (of both the user and his or her contacts) will be displayed in Lync 2010. Valid settings are:
NoPhoto - Photos are not displayed in Lync 2010.
PhotosFromADOnly - Only photos that have been published in Active Directory Domain Services (AD DS) can be displayed.
AllPhotos - Either Active Directory photos or custom photos can be displayed.
The default value is AllPhotos.
Hi Mark, yes CsClientPolicy work well, and I just set PhotosFromADOnly. But any user still have the choice "do not show my picture" in the Lync client option.
I need that user pictore is always on.
Thanks
Regards
Pietro
Please visit the below link to see the various paid support options that are available to better meet your needs. http://support.microsoft.com/default.aspx?id=fh;en-us;offerprophone
There are many of us who administer Lync that need to disable "Do not show my picture" and force users to use the Corporate Photo. Let me know when someone beats this... Thanks!
There are many of us who administer Lync that need to disable "Do not show my picture" and force users to use the Corporate Photo. Let me know when someone beats this... Thanks!
Just in case someone from the Lync product group see's this allow me to also add that is absolutely becoming a requirement in our business, especially after inversting in Lync and setting up a process to add pictures to AD, having users able to disable the picture completely eliminates a lot of Lync's value.
For those of you who strongly have a business case for this feature, how many users are affected in your respective organizations?
For Lee;
Potential of 200+ users at this time. More depending on the adoption rate.
larry
200+
As we have offices all throughout Canada, it is considered important that employees remain connected through IM and SharePoint, and the ability to see pictures of all employees, especially remote ones, enables those working together to put a face to the name.
I would also really like to see a fix for this as we are getting the same issues as everybody else here - 2000 users.
Thanks,
John
3500+ We are rolling out globally, and replacing SPARC. We need to force the use of the internal badge pictures as part of corporate policy.
d
For those of you who strongly have a business case for this feature, how many users are affected in your respective organizations?
hmmm... yes i see what u mean... i too am looking
hmmm... yes i see what u mean... i too am looking
hmmm... yes i see what u mean... i too am looking
hmmm... yes i see what u mean... i too am looking
hmmm... yes i see what u mean... i too am looking
has anyone had any success with this method?
http://iconraja.wordpress.com/2010/12/20/forcing-active-directory-photos-with-lync-2010/
seems like it would work, just a bit drawn out.
This doesn't stop users from disabling the photo once it is forced down from AD :)
That is the setting that we all need--users can't select "No Photo" on their Lync client--we need a policy to disable that.
We've rolled out to trial users and as soon as they discover this setting, half of them select no Photo--so we have blank spaces where photos should be in Lync.
hmmm... yes i see what u mean... i too am looking
So far i am in a holding pattern... the MS Product Manager stated.... "I contacted one of our Lync engineers to research your question. He has also reached out to the Product Group for input, but his contact is on vacation until Aug 1<sup>st</sup>. "
will keep you updated....
Yes, our company doesn't allow users to do any kind of modification to their SharePoint photos, nor to choose NOT to display them: Why does Lync allow users to choose to not display their photo in an end-user setting that administrators can't modify? Sloppy.
Yes, our company doesn't allow users to do any kind of modification to their SharePoint photos, nor to choose NOT to display them: Why does Lync allow users to choose to not display their photo in an end-user setting that administrators can't modify? Sloppy.
Yes, our company doesn't allow users to do any kind of modification to their SharePoint photos, nor to choose NOT to display them: Why does Lync allow users to choose to not display their photo in an end-user setting that administrators can't modify? Sloppy.
Yes, our company doesn't allow users to do any kind of modification to their SharePoint photos, nor to choose NOT to display them: Why does Lync allow users to choose to not display their photo in an end-user setting that administrators can't modify? Sloppy.
Yes, our company doesn't allow users to do any kind of modification to their SharePoint photos, nor to choose NOT to display them: Why does Lync allow users to choose to not display their photo in an end-user setting that administrators can't modify? Sloppy.
I'm still looking for a way to do this. This a SECURITY issue in my organization. We have many temps coming in and out, and we require our users to be able to recognize a new temp by their Lync picture! The ability to hide the picture, while modest, is a security problem!!!
I can't choose to hide the photo on my ID card. This is the same type of issue here.
Oh, and for Desmond Lee, we have about 1800 users affected.
Yes, our company doesn't allow users to do any kind of modification to their SharePoint photos, nor to choose NOT to display them: Why does Lync allow users to choose to not display their photo in an end-user setting that administrators can't modify? Sloppy.
This certainly isn't a perfect fix - but I've figured out that you can use the dbimpexp tool to export a clients configuration to an xml file, replace the "FALSE" setting on the photo parameter with a "TRUE", and re-import the configuration again.
Next time the user logs in, their photo is displayed again. Our users soon got tired of hiding it every day.
Hopefully Microsoft sees fit to give us a GPO option to fix this in Wave 15.
This certainly isn't a perfect fix - but I've figured out that you can use the dbimpexp tool to export a clients configuration to an xml file, replace the "FALSE" setting on the photo parameter with a "TRUE", and re-import the configuration again.
Next time the user logs in, their photo is displayed again. Our users soon got tired of hiding it every day.
Hopefully Microsoft sees fit to give us a GPO option to fix this in Wave 15.
This certainly isn't a perfect fix - but I've figured out that you can use the dbimpexp tool to export a clients configuration to an xml file, replace the "FALSE" setting on the photo parameter with a "TRUE", and re-import the configuration again.
Next time the user logs in, their photo is displayed again. Our users soon got tired of hiding it every day.
Hopefully Microsoft sees fit to give us a GPO option to fix this in Wave 15.
This certainly isn't a perfect fix - but I've figured out that you can use the dbimpexp tool to export a clients configuration to an xml file, replace the "FALSE" setting on the photo parameter with a "TRUE", and re-import the configuration again.
Next time the user logs in, their photo is displayed again. Our users soon got tired of hiding it every day.
Hopefully Microsoft sees fit to give us a GPO option to fix this in Wave 15.
This certainly isn't a perfect fix - but I've figured out that you can use the dbimpexp tool to export a clients configuration to an xml file, replace the "FALSE" setting on the photo parameter with a "TRUE", and re-import the configuration again.
Next time the user logs in, their photo is displayed again. Our users soon got tired of hiding it every day.
Hopefully Microsoft sees fit to give us a GPO option to fix this in Wave 15.
This certainly isn't a perfect fix - but I've figured out that you can use the dbimpexp tool to export a clients configuration to an xml file, replace the "FALSE" setting on the photo parameter with a "TRUE", and re-import the configuration again.
Next time the user logs in, their photo is displayed again. Our users soon got tired of hiding it every day.
Hopefully Microsoft sees fit to give us a GPO option to fix this in Wave 15.
Can you post the script you created for dbimpexp?
Right now I'm thinking the solution is to run dbimpexp and export the entire database, then find/replace "<displayADPhoto>false</displayADPhoto>" and re-import?
This certainly isn't a perfect fix - but I've figured out that you can use the dbimpexp tool to export a clients configuration to an xml file, replace the "FALSE" setting on the photo parameter with a "TRUE", and re-import the configuration again.
Next time the user logs in, their photo is displayed again. Our users soon got tired of hiding it every day.
Hopefully Microsoft sees fit to give us a GPO option to fix this in Wave 15.
Indeed. Great workaround. I've written the following PowerShell script for modifying the XML, because I wanted to update the Version and LastPubTime, like happens when you modify this setting through Lync.
If (Test-Path 'C:\scripts\Export.xml') { Remove-Item 'C:\scripts\Export.xml' }
If (Test-Path 'C:\scripts\Import.xml') { Remove-Item 'C:\scripts\Import.xml' }
"Exporting users..."
$p = [diagnostics.process]::start('"C:\Program Files\Common Files\Microsoft Lync Server 2010\Support\DBImpExp.exe"', "/hrxmlfile:c:\scripts\Export.xml /sqlserver:sqlserver /restype:user")
$p.WaitForExit()
"Loading xml"
$d = [xml] (Get-Content C:\scripts\Export.xml)
"Processing..."
$changes = 0
foreach ($hr in $d.HomedResources.HomedResource)
{
foreach ($c in $hr.Containers.Container)
{
foreach ($p in $c.Publication)
{
if ($p.CategoryName -eq 'contactCard' -and $p.InstanceNum -eq 6 -and $p.Data.contactCard.displayADPhoto -eq 'false')
{
$hr.UserAtHost
$p.Data.contactCard.displayADPhoto = 'true'
$p.Version = (([int] $p.Version) + 1).ToString()
$p.PrevPubTime = $p.LastPubTime
$p.LastPubTime = (Get-Date -Format s).ToString()
$changes++
}
}
}
}
"Changes: $changes"
if ($changes -ne 0)
{
"Saving xml"
$d.Save("C:\scripts\Import.xml")
"Importing users..."
$p = [diagnostics.process]::start('"C:\Program Files\Common Files\Microsoft Lync Server 2010\Support\DBImpExp.exe"', "/import /hrxmlfile:c:\scripts\Import.xml /sqlserver:sqlserver /restype:user")
$p.WaitForExit()
}
"Done"
Gerard, if it isn't terribly complicated, could you explain how to execute this code block?
Pretend I have absolutely no idea how to even begin using scripts. :)
Thanks!
kyle
The easiest way is to create a folder C:\scripts, then Copy/Paste it to Notepad, and then modify the sqlserver name (or remove the attribute for SE).Gerard, if it isn't terribly complicated, could you explain how to execute this code block?
Pretend I have absolutely no idea how to even begin using scripts. :)
Thanks!
kyle
This has worked for me also... Do you know if it runs while a user is logged in will it display their picture or do they need to close and reopen to take effect?
on side note, MS Developers have replied to the escalation i raised, and stated they do not have the option, nor do they have it in their immediate plans to add this feature.
One more thing that's worth mentioning is that you cannot call the script directly in a scheduled task.
If you want to run this as a scheduled task you will need to run it as:
powershell.exe -command "& 'c:\scripts\DisplayADPhoto.ps1'"
What's with the & ?
powershell -command c:\scripts\DisplayAdPhoto.ps1 works just fine....
Hello,
our company would also highly appreciate a fix for this. we do not want users to be able to disable the foto.
br
Hello,
i modified the script so it only uploads the users that have been changed:
foreach ($hr in $d.HomedResources.HomedResource) { $found = 0 foreach ($c in $hr.Containers.Container) { foreach ($p in $c.Publication) { if ($p.CategoryName -eq 'contactCard' -and $p.InstanceNum -eq 6 -and $p.Data.contactCard.displayADPhoto -eq 'false') { $hr.UserAtHost $p.Data.contactCard.displayADPhoto = 'true' $p.Version = (([int] $p.Version) + 1).ToString() $p.PrevPubTime = $p.LastPubTime $p.LastPubTime = (Get-Date -Format s).ToString() $found = 1 $changes++ } } } if ($found -eq 0) { [Void]$d.HomedResources.RemoveChild($hr) } }
thanks and br
Hello,
i modified the script so it only uploads the users that have been changed:
foreach ($hr in $d.HomedResources.HomedResource) { $found = 0 foreach ($c in $hr.Containers.Container) { foreach ($p in $c.Publication) { if ($p.CategoryName -eq 'contactCard' -and $p.InstanceNum -eq 6 -and $p.Data.contactCard.displayADPhoto -eq 'false') { $hr.UserAtHost $p.Data.contactCard.displayADPhoto = 'true' $p.Version = (([int] $p.Version) + 1).ToString() $p.PrevPubTime = $p.LastPubTime $p.LastPubTime = (Get-Date -Format s).ToString() $found = 1 $changes++ } } } if ($found -eq 0) { [Void]$d.HomedResources.RemoveChild($hr) } }
thanks and br
Hello,
i modified the script so it only uploads the users that have been changed:
foreach ($hr in $d.HomedResources.HomedResource) { $found = 0 foreach ($c in $hr.Containers.Container) { foreach ($p in $c.Publication) { if ($p.CategoryName -eq 'contactCard' -and $p.InstanceNum -eq 6 -and $p.Data.contactCard.displayADPhoto -eq 'false') { $hr.UserAtHost $p.Data.contactCard.displayADPhoto = 'true' $p.Version = (([int] $p.Version) + 1).ToString() $p.PrevPubTime = $p.LastPubTime $p.LastPubTime = (Get-Date -Format s).ToString() $found = 1 $changes++ } } } if ($found -eq 0) { [Void]$d.HomedResources.RemoveChild($hr) } }
thanks and br
Hello,
i modified the script so it only uploads the users that have been changed:
foreach ($hr in $d.HomedResources.HomedResource) { $found = 0 foreach ($c in $hr.Containers.Container) { foreach ($p in $c.Publication) { if ($p.CategoryName -eq 'contactCard' -and $p.InstanceNum -eq 6 -and $p.Data.contactCard.displayADPhoto -eq 'false') { $hr.UserAtHost $p.Data.contactCard.displayADPhoto = 'true' $p.Version = (([int] $p.Version) + 1).ToString() $p.PrevPubTime = $p.LastPubTime $p.LastPubTime = (Get-Date -Format s).ToString() $found = 1 $changes++ } } } if ($found -eq 0) { [Void]$d.HomedResources.RemoveChild($hr) } }
thanks and br
Hello,
i modified the script so it only uploads the users that have been changed:
foreach ($hr in $d.HomedResources.HomedResource) { $found = 0 foreach ($c in $hr.Containers.Container) { foreach ($p in $c.Publication) { if ($p.CategoryName -eq 'contactCard' -and $p.InstanceNum -eq 6 -and $p.Data.contactCard.displayADPhoto -eq 'false') { $hr.UserAtHost $p.Data.contactCard.displayADPhoto = 'true' $p.Version = (([int] $p.Version) + 1).ToString() $p.PrevPubTime = $p.LastPubTime $p.LastPubTime = (Get-Date -Format s).ToString() $found = 1 $changes++ } } } if ($found -eq 0) { [Void]$d.HomedResources.RemoveChild($hr) } }
thanks and br
Hello,
i modified the script so it only uploads the users that have been changed:
foreach ($hr in $d.HomedResources.HomedResource) { $found = 0 foreach ($c in $hr.Containers.Container) { foreach ($p in $c.Publication) { if ($p.CategoryName -eq 'contactCard' -and $p.InstanceNum -eq 6 -and $p.Data.contactCard.displayADPhoto -eq 'false') { $hr.UserAtHost $p.Data.contactCard.displayADPhoto = 'true' $p.Version = (([int] $p.Version) + 1).ToString() $p.PrevPubTime = $p.LastPubTime $p.LastPubTime = (Get-Date -Format s).ToString() $found = 1 $changes++ } } } if ($found -eq 0) { [Void]$d.HomedResources.RemoveChild($hr) } }
thanks and br
Hi,
Even we are looking for a solution on this.
More then 7000 users will be affected.
Hope Mircrosoft provides a solution through GPO.
Eagerly waiting.
Thanks,
Amit.
Hi All,
My recommendation for all that have deemed this a business requirement is to escalate this feature request through your Microsoft account managers so the UC product group receives your feedback.
I have tried the scripts listed in this thread and I continue to get the following:
Get-Content : Cannot find path 'C:\Scripts\Export.xml' because it does not exist.
At C:\scripts\ADPhoto.ps1:9 char:24
+ $d = [xml] (Get-Content <<<< C:\Scripts\Export.xml)
+ CategoryInfo : ObjectNotFound: (C:\Scripts\Export.xml:String) [Get-Content], ItemNotFoundException
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetContentCommand
Processing...
Changes: 0
Done
It doesn't seem to be producing the XML ?
Yep I certainly have permissions to write to the directory.
For the /sqlserver:sqlserver I have changed this to read:
/sqlserver:localhost ?
Is this correct?
Try this script, I've edited it to make it a little clearer what areas need to be changed.
# script to re-enable AD photos for users that have disabled them # DNS Name of SQL Server - Leave Blank for SQL Server Express $sqlserver = '' # This is the directory where exports will be placed temporarily - you must have write access to this directory $exportdir = 'C:\Lync-Scripts' ########## DO NOT EDIT BELOW THIS LINE ########## "Checking for Export Directory" If (-not (Test-Path "$exportdir" -pathType container)) { "ERROR: Your Export Directory doesn't exist!" Exit } "Cleaning up old files..." If (Test-Path "$exportdir\Export-Pictures.xml") { Remove-Item "$exportdir\Export-Pictures.xml" } If (Test-Path "$exportdir\Import-Pictures.xml") { Remove-Item "$exportdir\Import-Pictures.xml" } # check to see if we need to have an sqlserver argument to DBImpExp If ($sqlserver -ne "") { "Query will be run against SQL server ""$sqlserver""" $sqlserver = "/sqlserver:$sqlserver" } "Exporting users..." $p = [diagnostics.process]::start('"C:\Program Files\Common Files\Microsoft Lync Server 2010\Support\DBImpExp.exe"', "/hrxmlfile:""$exportdir\Export-Pictures.xml"" /restype:user $sqlserver") $p.WaitForExit() # check that XML was exported If (-not (Test-Path "$exportdir\Export-Pictures.xml" -pathType leaf)) { "ERROR: Verify that $exportdir is writable!" Exit } "Loading XML" $d = [xml] (Get-Content "$exportdir\Export-Pictures.xml") "Processing..." $changes = 0 foreach ($hr in $d.HomedResources.HomedResource) { $found = 0 foreach ($c in $hr.Containers.Container) { foreach ($p in $c.Publication) { If ($p.CategoryName -eq 'contactCard' -and $p.InstanceNum -eq 6 -and $p.Data.contactCard.displayADPhoto -eq 'false') { $hr.UserAtHost $p.Data.contactCard.displayADPhoto = 'true' $p.Version = (([int] $p.Version) + 1).ToString() $p.PrevPubTime = $p.LastPubTime $p.LastPubTime = (Get-Date -Format s).ToString() $found = 1 $changes++ } } } If ($found -eq 0) { [Void]$d.HomedResources.RemoveChild($hr) } } "Changes: $changes" If ($changes -ne 0) { "Saving XML..." $d.Save("$exportdir\Import-Pictures.xml") "Importing users..." $p = [diagnostics.process]::start('"C:\Program Files\Common Files\Microsoft Lync Server 2010\Support\DBImpExp.exe"', "/import /hrxmlfile:""$exportdir\Import-Pictures.xml"" /restype:user $sqlserver") $p.WaitForExit() } "Finished import, cleaning up..." If (Test-Path "$exportdir\Export-Pictures.xml") { Remove-Item "$exportdir\Export-Pictures.xml" } If (Test-Path "$exportdir\Import-Pictures.xml") { Remove-Item "$exportdir\Import-Pictures.xml" } "Done"
Try this script, I've edited it to make it a little clearer what areas need to be changed.
# script to re-enable AD photos for users that have disabled them # DNS Name of SQL Server - Leave Blank for SQL Server Express $sqlserver = '' # This is the directory where exports will be placed temporarily - you must have write access to this directory $exportdir = 'C:\Lync-Scripts' ########## DO NOT EDIT BELOW THIS LINE ########## "Checking for Export Directory" If (-not (Test-Path "$exportdir" -pathType container)) { "ERROR: Your Export Directory doesn't exist!" Exit } "Cleaning up old files..." If (Test-Path "$exportdir\Export-Pictures.xml") { Remove-Item "$exportdir\Export-Pictures.xml" } If (Test-Path "$exportdir\Import-Pictures.xml") { Remove-Item "$exportdir\Import-Pictures.xml" } # check to see if we need to have an sqlserver argument to DBImpExp If ($sqlserver -ne "") { "Query will be run against SQL server ""$sqlserver""" $sqlserver = "/sqlserver:$sqlserver" } "Exporting users..." $p = [diagnostics.process]::start('"C:\Program Files\Common Files\Microsoft Lync Server 2010\Support\DBImpExp.exe"', "/hrxmlfile:""$exportdir\Export-Pictures.xml"" /restype:user $sqlserver") $p.WaitForExit() # check that XML was exported If (-not (Test-Path "$exportdir\Export-Pictures.xml" -pathType leaf)) { "ERROR: Verify that $exportdir is writable!" Exit } "Loading XML" $d = [xml] (Get-Content "$exportdir\Export-Pictures.xml") "Processing..." $changes = 0 foreach ($hr in $d.HomedResources.HomedResource) { $found = 0 foreach ($c in $hr.Containers.Container) { foreach ($p in $c.Publication) { If ($p.CategoryName -eq 'contactCard' -and $p.InstanceNum -eq 6 -and $p.Data.contactCard.displayADPhoto -eq 'false') { $hr.UserAtHost $p.Data.contactCard.displayADPhoto = 'true' $p.Version = (([int] $p.Version) + 1).ToString() $p.PrevPubTime = $p.LastPubTime $p.LastPubTime = (Get-Date -Format s).ToString() $found = 1 $changes++ } } } If ($found -eq 0) { [Void]$d.HomedResources.RemoveChild($hr) } } "Changes: $changes" If ($changes -ne 0) { "Saving XML..." $d.Save("$exportdir\Import-Pictures.xml") "Importing users..." $p = [diagnostics.process]::start('"C:\Program Files\Common Files\Microsoft Lync Server 2010\Support\DBImpExp.exe"', "/import /hrxmlfile:""$exportdir\Import-Pictures.xml"" /restype:user $sqlserver") $p.WaitForExit() } "Finished import, cleaning up..." If (Test-Path "$exportdir\Export-Pictures.xml") { Remove-Item "$exportdir\Export-Pictures.xml" } If (Test-Path "$exportdir\Import-Pictures.xml") { Remove-Item "$exportdir\Import-Pictures.xml" } "Done"
Try this script, I've edited it to make it a little clearer what areas need to be changed.
# script to re-enable AD photos for users that have disabled them # DNS Name of SQL Server - Leave Blank for SQL Server Express $sqlserver = '' # This is the directory where exports will be placed temporarily - you must have write access to this directory $exportdir = 'C:\Lync-Scripts' ########## DO NOT EDIT BELOW THIS LINE ########## "Checking for Export Directory" If (-not (Test-Path "$exportdir" -pathType container)) { "ERROR: Your Export Directory doesn't exist!" Exit } "Cleaning up old files..." If (Test-Path "$exportdir\Export-Pictures.xml") { Remove-Item "$exportdir\Export-Pictures.xml" } If (Test-Path "$exportdir\Import-Pictures.xml") { Remove-Item "$exportdir\Import-Pictures.xml" } # check to see if we need to have an sqlserver argument to DBImpExp If ($sqlserver -ne "") { "Query will be run against SQL server ""$sqlserver""" $sqlserver = "/sqlserver:$sqlserver" } "Exporting users..." $p = [diagnostics.process]::start('"C:\Program Files\Common Files\Microsoft Lync Server 2010\Support\DBImpExp.exe"', "/hrxmlfile:""$exportdir\Export-Pictures.xml"" /restype:user $sqlserver") $p.WaitForExit() # check that XML was exported If (-not (Test-Path "$exportdir\Export-Pictures.xml" -pathType leaf)) { "ERROR: Verify that $exportdir is writable!" Exit } "Loading XML" $d = [xml] (Get-Content "$exportdir\Export-Pictures.xml") "Processing..." $changes = 0 foreach ($hr in $d.HomedResources.HomedResource) { $found = 0 foreach ($c in $hr.Containers.Container) { foreach ($p in $c.Publication) { If ($p.CategoryName -eq 'contactCard' -and $p.InstanceNum -eq 6 -and $p.Data.contactCard.displayADPhoto -eq 'false') { $hr.UserAtHost $p.Data.contactCard.displayADPhoto = 'true' $p.Version = (([int] $p.Version) + 1).ToString() $p.PrevPubTime = $p.LastPubTime $p.LastPubTime = (Get-Date -Format s).ToString() $found = 1 $changes++ } } } If ($found -eq 0) { [Void]$d.HomedResources.RemoveChild($hr) } } "Changes: $changes" If ($changes -ne 0) { "Saving XML..." $d.Save("$exportdir\Import-Pictures.xml") "Importing users..." $p = [diagnostics.process]::start('"C:\Program Files\Common Files\Microsoft Lync Server 2010\Support\DBImpExp.exe"', "/import /hrxmlfile:""$exportdir\Import-Pictures.xml"" /restype:user $sqlserver") $p.WaitForExit() } "Finished import, cleaning up..." If (Test-Path "$exportdir\Export-Pictures.xml") { Remove-Item "$exportdir\Export-Pictures.xml" } If (Test-Path "$exportdir\Import-Pictures.xml") { Remove-Item "$exportdir\Import-Pictures.xml" } "Done"
Try this script, I've edited it to make it a little clearer what areas need to be changed.
# script to re-enable AD photos for users that have disabled them # DNS Name of SQL Server - Leave Blank for SQL Server Express $sqlserver = '' # This is the directory where exports will be placed temporarily - you must have write access to this directory $exportdir = 'C:\Lync-Scripts' ########## DO NOT EDIT BELOW THIS LINE ########## "Checking for Export Directory" If (-not (Test-Path "$exportdir" -pathType container)) { "ERROR: Your Export Directory doesn't exist!" Exit } "Cleaning up old files..." If (Test-Path "$exportdir\Export-Pictures.xml") { Remove-Item "$exportdir\Export-Pictures.xml" } If (Test-Path "$exportdir\Import-Pictures.xml") { Remove-Item "$exportdir\Import-Pictures.xml" } # check to see if we need to have an sqlserver argument to DBImpExp If ($sqlserver -ne "") { "Query will be run against SQL server ""$sqlserver""" $sqlserver = "/sqlserver:$sqlserver" } "Exporting users..." $p = [diagnostics.process]::start('"C:\Program Files\Common Files\Microsoft Lync Server 2010\Support\DBImpExp.exe"', "/hrxmlfile:""$exportdir\Export-Pictures.xml"" /restype:user $sqlserver") $p.WaitForExit() # check that XML was exported If (-not (Test-Path "$exportdir\Export-Pictures.xml" -pathType leaf)) { "ERROR: Verify that $exportdir is writable!" Exit } "Loading XML" $d = [xml] (Get-Content "$exportdir\Export-Pictures.xml") "Processing..." $changes = 0 foreach ($hr in $d.HomedResources.HomedResource) { $found = 0 foreach ($c in $hr.Containers.Container) { foreach ($p in $c.Publication) { If ($p.CategoryName -eq 'contactCard' -and $p.InstanceNum -eq 6 -and $p.Data.contactCard.displayADPhoto -eq 'false') { $hr.UserAtHost $p.Data.contactCard.displayADPhoto = 'true' $p.Version = (([int] $p.Version) + 1).ToString() $p.PrevPubTime = $p.LastPubTime $p.LastPubTime = (Get-Date -Format s).ToString() $found = 1 $changes++ } } } If ($found -eq 0) { [Void]$d.HomedResources.RemoveChild($hr) } } "Changes: $changes" If ($changes -ne 0) { "Saving XML..." $d.Save("$exportdir\Import-Pictures.xml") "Importing users..." $p = [diagnostics.process]::start('"C:\Program Files\Common Files\Microsoft Lync Server 2010\Support\DBImpExp.exe"', "/import /hrxmlfile:""$exportdir\Import-Pictures.xml"" /restype:user $sqlserver") $p.WaitForExit() } "Finished import, cleaning up..." If (Test-Path "$exportdir\Export-Pictures.xml") { Remove-Item "$exportdir\Export-Pictures.xml" } If (Test-Path "$exportdir\Import-Pictures.xml") { Remove-Item "$exportdir\Import-Pictures.xml" } "Done"
Try this script, I've edited it to make it a little clearer what areas need to be changed.
# script to re-enable AD photos for users that have disabled them # DNS Name of SQL Server - Leave Blank for SQL Server Express $sqlserver = '' # This is the directory where exports will be placed temporarily - you must have write access to this directory $exportdir = 'C:\Lync-Scripts' ########## DO NOT EDIT BELOW THIS LINE ########## "Checking for Export Directory" If (-not (Test-Path "$exportdir" -pathType container)) { "ERROR: Your Export Directory doesn't exist!" Exit } "Cleaning up old files..." If (Test-Path "$exportdir\Export-Pictures.xml") { Remove-Item "$exportdir\Export-Pictures.xml" } If (Test-Path "$exportdir\Import-Pictures.xml") { Remove-Item "$exportdir\Import-Pictures.xml" } # check to see if we need to have an sqlserver argument to DBImpExp If ($sqlserver -ne "") { "Query will be run against SQL server ""$sqlserver""" $sqlserver = "/sqlserver:$sqlserver" } "Exporting users..." $p = [diagnostics.process]::start('"C:\Program Files\Common Files\Microsoft Lync Server 2010\Support\DBImpExp.exe"', "/hrxmlfile:""$exportdir\Export-Pictures.xml"" /restype:user $sqlserver") $p.WaitForExit() # check that XML was exported If (-not (Test-Path "$exportdir\Export-Pictures.xml" -pathType leaf)) { "ERROR: Verify that $exportdir is writable!" Exit } "Loading XML" $d = [xml] (Get-Content "$exportdir\Export-Pictures.xml") "Processing..." $changes = 0 foreach ($hr in $d.HomedResources.HomedResource) { $found = 0 foreach ($c in $hr.Containers.Container) { foreach ($p in $c.Publication) { If ($p.CategoryName -eq 'contactCard' -and $p.InstanceNum -eq 6 -and $p.Data.contactCard.displayADPhoto -eq 'false') { $hr.UserAtHost $p.Data.contactCard.displayADPhoto = 'true' $p.Version = (([int] $p.Version) + 1).ToString() $p.PrevPubTime = $p.LastPubTime $p.LastPubTime = (Get-Date -Format s).ToString() $found = 1 $changes++ } } } If ($found -eq 0) { [Void]$d.HomedResources.RemoveChild($hr) } } "Changes: $changes" If ($changes -ne 0) { "Saving XML..." $d.Save("$exportdir\Import-Pictures.xml") "Importing users..." $p = [diagnostics.process]::start('"C:\Program Files\Common Files\Microsoft Lync Server 2010\Support\DBImpExp.exe"', "/import /hrxmlfile:""$exportdir\Import-Pictures.xml"" /restype:user $sqlserver") $p.WaitForExit() } "Finished import, cleaning up..." If (Test-Path "$exportdir\Export-Pictures.xml") { Remove-Item "$exportdir\Export-Pictures.xml" } If (Test-Path "$exportdir\Import-Pictures.xml") { Remove-Item "$exportdir\Import-Pictures.xml" } "Done"
Try this script, I've edited it to make it a little clearer what areas need to be changed.
# script to re-enable AD photos for users that have disabled them # DNS Name of SQL Server - Leave Blank for SQL Server Express $sqlserver = '' # This is the directory where exports will be placed temporarily - you must have write access to this directory $exportdir = 'C:\Lync-Scripts' ########## DO NOT EDIT BELOW THIS LINE ########## "Checking for Export Directory" If (-not (Test-Path "$exportdir" -pathType container)) { "ERROR: Your Export Directory doesn't exist!" Exit } "Cleaning up old files..." If (Test-Path "$exportdir\Export-Pictures.xml") { Remove-Item "$exportdir\Export-Pictures.xml" } If (Test-Path "$exportdir\Import-Pictures.xml") { Remove-Item "$exportdir\Import-Pictures.xml" } # check to see if we need to have an sqlserver argument to DBImpExp If ($sqlserver -ne "") { "Query will be run against SQL server ""$sqlserver""" $sqlserver = "/sqlserver:$sqlserver" } "Exporting users..." $p = [diagnostics.process]::start('"C:\Program Files\Common Files\Microsoft Lync Server 2010\Support\DBImpExp.exe"', "/hrxmlfile:""$exportdir\Export-Pictures.xml"" /restype:user $sqlserver") $p.WaitForExit() # check that XML was exported If (-not (Test-Path "$exportdir\Export-Pictures.xml" -pathType leaf)) { "ERROR: Verify that $exportdir is writable!" Exit } "Loading XML" $d = [xml] (Get-Content "$exportdir\Export-Pictures.xml") "Processing..." $changes = 0 foreach ($hr in $d.HomedResources.HomedResource) { $found = 0 foreach ($c in $hr.Containers.Container) { foreach ($p in $c.Publication) { If ($p.CategoryName -eq 'contactCard' -and $p.InstanceNum -eq 6 -and $p.Data.contactCard.displayADPhoto -eq 'false') { $hr.UserAtHost $p.Data.contactCard.displayADPhoto = 'true' $p.Version = (([int] $p.Version) + 1).ToString() $p.PrevPubTime = $p.LastPubTime $p.LastPubTime = (Get-Date -Format s).ToString() $found = 1 $changes++ } } } If ($found -eq 0) { [Void]$d.HomedResources.RemoveChild($hr) } } "Changes: $changes" If ($changes -ne 0) { "Saving XML..." $d.Save("$exportdir\Import-Pictures.xml") "Importing users..." $p = [diagnostics.process]::start('"C:\Program Files\Common Files\Microsoft Lync Server 2010\Support\DBImpExp.exe"', "/import /hrxmlfile:""$exportdir\Import-Pictures.xml"" /restype:user $sqlserver") $p.WaitForExit() } "Finished import, cleaning up..." If (Test-Path "$exportdir\Export-Pictures.xml") { Remove-Item "$exportdir\Export-Pictures.xml" } If (Test-Path "$exportdir\Import-Pictures.xml") { Remove-Item "$exportdir\Import-Pictures.xml" } "Done"
Worked perfectly Shannon.
Many Thanks!
I did have one user that threw off an error on this:
Property 'PrevPubTime' cannot be found on this object; make sure it exists and is settable.
Are all these settings in Active Directory?
Thanks for any help.
Add me as well
1000+ users
Dave
Add me as well
600+ users
Hi Des,
Have you got any news on this, is it still worth posting?
Cheers
Great!
Thanks for the script. Is possible to add some logging functions - how many people was updated a who?
Thank you for your response
jcerny
We have about 150 users and would also like to make sure users don't have the ability to turn off the corporate photo.
Thanks,
Shannon - we use Lync 2010 in Office 365 (hosted). I assume it's not possible to apply your solution in this case since I don't technically have a Lync server?
Thanks,
lunchroom
looks like some basic powershell can be done with office365:
http://blog.insidelync.com/2011/09/handy-powershell-administration-script-for-office-365-2/
1500 Corporate/Office based Users. 6000 or so in non office locations, so we need to see their faces as we rarely come into contact with them day to day.
When I run the script I get 4 lines for each user than has a change made, any ideas what causes this?
e.g. say matth@domain.co.uk changed his settings I would get
matth@domain.co.uk
matth@domain.co.uk
matth@domain.co.uk
matth@domain.co.uk
Changes: 4
So, I did some checking and it looks like each user's contact card is in the exported XML multiple times. Here is an updated script that checks to see if the last user name that was printed is the same as the one that is currently being worked on, and if so it skips outputting the name. This is just a cosmetic change from the last version of the script.
# script to re-enable AD photos for users that have disabled them # DNS Name of SQL Server - Leave Blank for SQL Server Express $sqlserver = '' # This is the directory where exports will be placed temporarily - you must have write access to this directory $exportdir = 'C:\Lync-Scripts' ########## DO NOT EDIT BELOW THIS LINE ########## "Checking for Export Directory" If (-not (Test-Path "$exportdir" -pathType container)) { "ERROR: Your Export Directory doesn't exist!" Exit } "Cleaning up old files..." If (Test-Path "$exportdir\Export-Pictures.xml") { Remove-Item "$exportdir\Export-Pictures.xml" } If (Test-Path "$exportdir\Import-Pictures.xml") { Remove-Item "$exportdir\Import-Pictures.xml" } # check to see if we need to have an sqlserver argument to DBImpExp If ($sqlserver -ne "") { "Query will be run against SQL server ""$sqlserver""" $sqlserver = "/sqlserver:$sqlserver" } "Exporting users..." $p = [diagnostics.process]::start('"C:\Program Files\Common Files\Microsoft Lync Server 2010\Support\DBImpExp.exe"', "/hrxmlfile:""$exportdir\Export-Pictures.xml"" /restype:user $sqlserver") $p.WaitForExit() # check that XML was exported If (-not (Test-Path "$exportdir\Export-Pictures.xml" -pathType leaf)) { "ERROR: Verify that $exportdir is writable!" Exit } "Loading XML" $d = [xml] (Get-Content "$exportdir\Export-Pictures.xml") "Processing..." $changes = 0 $lastProcessedUser = $null foreach ($hr in $d.HomedResources.HomedResource) { $found = 0 foreach ($c in $hr.Containers.Container) { foreach ($p in $c.Publication) { If ($p.CategoryName -eq 'contactCard' -and $p.InstanceNum -eq 6 -and $p.Data.contactCard.displayADPhoto -eq 'false') { If ($hr.UserAtHost -ne $lastProcessedUser) { "$($hr.UserAtHost) reset" $lastProcessedUser = $hr.UserAtHost } $p.Data.contactCard.displayADPhoto = 'true' $p.Version = (([int] $p.Version) + 1).ToString() $p.PrevPubTime = $p.LastPubTime $p.LastPubTime = (Get-Date -Format s).ToString() $found = 1 $changes++ } } } If ($found -eq 0) { [Void]$d.HomedResources.RemoveChild($hr) } } "Changes: $changes" If ($changes -ne 0) { "Saving XML..." $d.Save("$exportdir\Import-Pictures.xml") "Importing users..." $p = [diagnostics.process]::start('"C:\Program Files\Common Files\Microsoft Lync Server 2010\Support\DBImpExp.exe"', "/import /hrxmlfile:""$exportdir\Import-Pictures.xml"" /restype:user $sqlserver") $p.WaitForExit() } "Finished import, cleaning up..." If (Test-Path "$exportdir\Export-Pictures.xml") { Remove-Item "$exportdir\Export-Pictures.xml" } If (Test-Path "$exportdir\Import-Pictures.xml") { Remove-Item "$exportdir\Import-Pictures.xml" } "Done"
So, I did some checking and it looks like each user's contact card is in the exported XML multiple times. Here is an updated script that checks to see if the last user name that was printed is the same as the one that is currently being worked on, and if so it skips outputting the name. This is just a cosmetic change from the last version of the script.
# script to re-enable AD photos for users that have disabled them # DNS Name of SQL Server - Leave Blank for SQL Server Express $sqlserver = '' # This is the directory where exports will be placed temporarily - you must have write access to this directory $exportdir = 'C:\Lync-Scripts' ########## DO NOT EDIT BELOW THIS LINE ########## "Checking for Export Directory" If (-not (Test-Path "$exportdir" -pathType container)) { "ERROR: Your Export Directory doesn't exist!" Exit } "Cleaning up old files..." If (Test-Path "$exportdir\Export-Pictures.xml") { Remove-Item "$exportdir\Export-Pictures.xml" } If (Test-Path "$exportdir\Import-Pictures.xml") { Remove-Item "$exportdir\Import-Pictures.xml" } # check to see if we need to have an sqlserver argument to DBImpExp If ($sqlserver -ne "") { "Query will be run against SQL server ""$sqlserver""" $sqlserver = "/sqlserver:$sqlserver" } "Exporting users..." $p = [diagnostics.process]::start('"C:\Program Files\Common Files\Microsoft Lync Server 2010\Support\DBImpExp.exe"', "/hrxmlfile:""$exportdir\Export-Pictures.xml"" /restype:user $sqlserver") $p.WaitForExit() # check that XML was exported If (-not (Test-Path "$exportdir\Export-Pictures.xml" -pathType leaf)) { "ERROR: Verify that $exportdir is writable!" Exit } "Loading XML" $d = [xml] (Get-Content "$exportdir\Export-Pictures.xml") "Processing..." $changes = 0 $lastProcessedUser = $null foreach ($hr in $d.HomedResources.HomedResource) { $found = 0 foreach ($c in $hr.Containers.Container) { foreach ($p in $c.Publication) { If ($p.CategoryName -eq 'contactCard' -and $p.InstanceNum -eq 6 -and $p.Data.contactCard.displayADPhoto -eq 'false') { If ($hr.UserAtHost -ne $lastProcessedUser) { "$($hr.UserAtHost) reset" $lastProcessedUser = $hr.UserAtHost } $p.Data.contactCard.displayADPhoto = 'true' $p.Version = (([int] $p.Version) + 1).ToString() $p.PrevPubTime = $p.LastPubTime $p.LastPubTime = (Get-Date -Format s).ToString() $found = 1 $changes++ } } } If ($found -eq 0) { [Void]$d.HomedResources.RemoveChild($hr) } } "Changes: $changes" If ($changes -ne 0) { "Saving XML..." $d.Save("$exportdir\Import-Pictures.xml") "Importing users..." $p = [diagnostics.process]::start('"C:\Program Files\Common Files\Microsoft Lync Server 2010\Support\DBImpExp.exe"', "/import /hrxmlfile:""$exportdir\Import-Pictures.xml"" /restype:user $sqlserver") $p.WaitForExit() } "Finished import, cleaning up..." If (Test-Path "$exportdir\Export-Pictures.xml") { Remove-Item "$exportdir\Export-Pictures.xml" } If (Test-Path "$exportdir\Import-Pictures.xml") { Remove-Item "$exportdir\Import-Pictures.xml" } "Done"
So, I did some checking and it looks like each user's contact card is in the exported XML multiple times. Here is an updated script that checks to see if the last user name that was printed is the same as the one that is currently being worked on, and if so it skips outputting the name. This is just a cosmetic change from the last version of the script.
# script to re-enable AD photos for users that have disabled them # DNS Name of SQL Server - Leave Blank for SQL Server Express $sqlserver = '' # This is the directory where exports will be placed temporarily - you must have write access to this directory $exportdir = 'C:\Lync-Scripts' ########## DO NOT EDIT BELOW THIS LINE ########## "Checking for Export Directory" If (-not (Test-Path "$exportdir" -pathType container)) { "ERROR: Your Export Directory doesn't exist!" Exit } "Cleaning up old files..." If (Test-Path "$exportdir\Export-Pictures.xml") { Remove-Item "$exportdir\Export-Pictures.xml" } If (Test-Path "$exportdir\Import-Pictures.xml") { Remove-Item "$exportdir\Import-Pictures.xml" } # check to see if we need to have an sqlserver argument to DBImpExp If ($sqlserver -ne "") { "Query will be run against SQL server ""$sqlserver""" $sqlserver = "/sqlserver:$sqlserver" } "Exporting users..." $p = [diagnostics.process]::start('"C:\Program Files\Common Files\Microsoft Lync Server 2010\Support\DBImpExp.exe"', "/hrxmlfile:""$exportdir\Export-Pictures.xml"" /restype:user $sqlserver") $p.WaitForExit() # check that XML was exported If (-not (Test-Path "$exportdir\Export-Pictures.xml" -pathType leaf)) { "ERROR: Verify that $exportdir is writable!" Exit } "Loading XML" $d = [xml] (Get-Content "$exportdir\Export-Pictures.xml") "Processing..." $changes = 0 $lastProcessedUser = $null foreach ($hr in $d.HomedResources.HomedResource) { $found = 0 foreach ($c in $hr.Containers.Container) { foreach ($p in $c.Publication) { If ($p.CategoryName -eq 'contactCard' -and $p.InstanceNum -eq 6 -and $p.Data.contactCard.displayADPhoto -eq 'false') { If ($hr.UserAtHost -ne $lastProcessedUser) { "$($hr.UserAtHost) reset" $lastProcessedUser = $hr.UserAtHost } $p.Data.contactCard.displayADPhoto = 'true' $p.Version = (([int] $p.Version) + 1).ToString() $p.PrevPubTime = $p.LastPubTime $p.LastPubTime = (Get-Date -Format s).ToString() $found = 1 $changes++ } } } If ($found -eq 0) { [Void]$d.HomedResources.RemoveChild($hr) } } "Changes: $changes" If ($changes -ne 0) { "Saving XML..." $d.Save("$exportdir\Import-Pictures.xml") "Importing users..." $p = [diagnostics.process]::start('"C:\Program Files\Common Files\Microsoft Lync Server 2010\Support\DBImpExp.exe"', "/import /hrxmlfile:""$exportdir\Import-Pictures.xml"" /restype:user $sqlserver") $p.WaitForExit() } "Finished import, cleaning up..." If (Test-Path "$exportdir\Export-Pictures.xml") { Remove-Item "$exportdir\Export-Pictures.xml" } If (Test-Path "$exportdir\Import-Pictures.xml") { Remove-Item "$exportdir\Import-Pictures.xml" } "Done"
So, I did some checking and it looks like each user's contact card is in the exported XML multiple times. Here is an updated script that checks to see if the last user name that was printed is the same as the one that is currently being worked on, and if so it skips outputting the name. This is just a cosmetic change from the last version of the script.
# script to re-enable AD photos for users that have disabled them # DNS Name of SQL Server - Leave Blank for SQL Server Express $sqlserver = '' # This is the directory where exports will be placed temporarily - you must have write access to this directory $exportdir = 'C:\Lync-Scripts' ########## DO NOT EDIT BELOW THIS LINE ########## "Checking for Export Directory" If (-not (Test-Path "$exportdir" -pathType container)) { "ERROR: Your Export Directory doesn't exist!" Exit } "Cleaning up old files..." If (Test-Path "$exportdir\Export-Pictures.xml") { Remove-Item "$exportdir\Export-Pictures.xml" } If (Test-Path "$exportdir\Import-Pictures.xml") { Remove-Item "$exportdir\Import-Pictures.xml" } # check to see if we need to have an sqlserver argument to DBImpExp If ($sqlserver -ne "") { "Query will be run against SQL server ""$sqlserver""" $sqlserver = "/sqlserver:$sqlserver" } "Exporting users..." $p = [diagnostics.process]::start('"C:\Program Files\Common Files\Microsoft Lync Server 2010\Support\DBImpExp.exe"', "/hrxmlfile:""$exportdir\Export-Pictures.xml"" /restype:user $sqlserver") $p.WaitForExit() # check that XML was exported If (-not (Test-Path "$exportdir\Export-Pictures.xml" -pathType leaf)) { "ERROR: Verify that $exportdir is writable!" Exit } "Loading XML" $d = [xml] (Get-Content "$exportdir\Export-Pictures.xml") "Processing..." $changes = 0 $lastProcessedUser = $null foreach ($hr in $d.HomedResources.HomedResource) { $found = 0 foreach ($c in $hr.Containers.Container) { foreach ($p in $c.Publication) { If ($p.CategoryName -eq 'contactCard' -and $p.InstanceNum -eq 6 -and $p.Data.contactCard.displayADPhoto -eq 'false') { If ($hr.UserAtHost -ne $lastProcessedUser) { "$($hr.UserAtHost) reset" $lastProcessedUser = $hr.UserAtHost } $p.Data.contactCard.displayADPhoto = 'true' $p.Version = (([int] $p.Version) + 1).ToString() $p.PrevPubTime = $p.LastPubTime $p.LastPubTime = (Get-Date -Format s).ToString() $found = 1 $changes++ } } } If ($found -eq 0) { [Void]$d.HomedResources.RemoveChild($hr) } } "Changes: $changes" If ($changes -ne 0) { "Saving XML..." $d.Save("$exportdir\Import-Pictures.xml") "Importing users..." $p = [diagnostics.process]::start('"C:\Program Files\Common Files\Microsoft Lync Server 2010\Support\DBImpExp.exe"', "/import /hrxmlfile:""$exportdir\Import-Pictures.xml"" /restype:user $sqlserver") $p.WaitForExit() } "Finished import, cleaning up..." If (Test-Path "$exportdir\Export-Pictures.xml") { Remove-Item "$exportdir\Export-Pictures.xml" } If (Test-Path "$exportdir\Import-Pictures.xml") { Remove-Item "$exportdir\Import-Pictures.xml" } "Done"
So, I did some checking and it looks like each user's contact card is in the exported XML multiple times. Here is an updated script that checks to see if the last user name that was printed is the same as the one that is currently being worked on, and if so it skips outputting the name. This is just a cosmetic change from the last version of the script.
# script to re-enable AD photos for users that have disabled them # DNS Name of SQL Server - Leave Blank for SQL Server Express $sqlserver = '' # This is the directory where exports will be placed temporarily - you must have write access to this directory $exportdir = 'C:\Lync-Scripts' ########## DO NOT EDIT BELOW THIS LINE ########## "Checking for Export Directory" If (-not (Test-Path "$exportdir" -pathType container)) { "ERROR: Your Export Directory doesn't exist!" Exit } "Cleaning up old files..." If (Test-Path "$exportdir\Export-Pictures.xml") { Remove-Item "$exportdir\Export-Pictures.xml" } If (Test-Path "$exportdir\Import-Pictures.xml") { Remove-Item "$exportdir\Import-Pictures.xml" } # check to see if we need to have an sqlserver argument to DBImpExp If ($sqlserver -ne "") { "Query will be run against SQL server ""$sqlserver""" $sqlserver = "/sqlserver:$sqlserver" } "Exporting users..." $p = [diagnostics.process]::start('"C:\Program Files\Common Files\Microsoft Lync Server 2010\Support\DBImpExp.exe"', "/hrxmlfile:""$exportdir\Export-Pictures.xml"" /restype:user $sqlserver") $p.WaitForExit() # check that XML was exported If (-not (Test-Path "$exportdir\Export-Pictures.xml" -pathType leaf)) { "ERROR: Verify that $exportdir is writable!" Exit } "Loading XML" $d = [xml] (Get-Content "$exportdir\Export-Pictures.xml") "Processing..." $changes = 0 $lastProcessedUser = $null foreach ($hr in $d.HomedResources.HomedResource) { $found = 0 foreach ($c in $hr.Containers.Container) { foreach ($p in $c.Publication) { If ($p.CategoryName -eq 'contactCard' -and $p.InstanceNum -eq 6 -and $p.Data.contactCard.displayADPhoto -eq 'false') { If ($hr.UserAtHost -ne $lastProcessedUser) { "$($hr.UserAtHost) reset" $lastProcessedUser = $hr.UserAtHost } $p.Data.contactCard.displayADPhoto = 'true' $p.Version = (([int] $p.Version) + 1).ToString() $p.PrevPubTime = $p.LastPubTime $p.LastPubTime = (Get-Date -Format s).ToString() $found = 1 $changes++ } } } If ($found -eq 0) { [Void]$d.HomedResources.RemoveChild($hr) } } "Changes: $changes" If ($changes -ne 0) { "Saving XML..." $d.Save("$exportdir\Import-Pictures.xml") "Importing users..." $p = [diagnostics.process]::start('"C:\Program Files\Common Files\Microsoft Lync Server 2010\Support\DBImpExp.exe"', "/import /hrxmlfile:""$exportdir\Import-Pictures.xml"" /restype:user $sqlserver") $p.WaitForExit() } "Finished import, cleaning up..." If (Test-Path "$exportdir\Export-Pictures.xml") { Remove-Item "$exportdir\Export-Pictures.xml" } If (Test-Path "$exportdir\Import-Pictures.xml") { Remove-Item "$exportdir\Import-Pictures.xml" } "Done"
So, I did some checking and it looks like each user's contact card is in the exported XML multiple times. Here is an updated script that checks to see if the last user name that was printed is the same as the one that is currently being worked on, and if so it skips outputting the name. This is just a cosmetic change from the last version of the script.
# script to re-enable AD photos for users that have disabled them # DNS Name of SQL Server - Leave Blank for SQL Server Express $sqlserver = '' # This is the directory where exports will be placed temporarily - you must have write access to this directory $exportdir = 'C:\Lync-Scripts' ########## DO NOT EDIT BELOW THIS LINE ########## "Checking for Export Directory" If (-not (Test-Path "$exportdir" -pathType container)) { "ERROR: Your Export Directory doesn't exist!" Exit } "Cleaning up old files..." If (Test-Path "$exportdir\Export-Pictures.xml") { Remove-Item "$exportdir\Export-Pictures.xml" } If (Test-Path "$exportdir\Import-Pictures.xml") { Remove-Item "$exportdir\Import-Pictures.xml" } # check to see if we need to have an sqlserver argument to DBImpExp If ($sqlserver -ne "") { "Query will be run against SQL server ""$sqlserver""" $sqlserver = "/sqlserver:$sqlserver" } "Exporting users..." $p = [diagnostics.process]::start('"C:\Program Files\Common Files\Microsoft Lync Server 2010\Support\DBImpExp.exe"', "/hrxmlfile:""$exportdir\Export-Pictures.xml"" /restype:user $sqlserver") $p.WaitForExit() # check that XML was exported If (-not (Test-Path "$exportdir\Export-Pictures.xml" -pathType leaf)) { "ERROR: Verify that $exportdir is writable!" Exit } "Loading XML" $d = [xml] (Get-Content "$exportdir\Export-Pictures.xml") "Processing..." $changes = 0 $lastProcessedUser = $null foreach ($hr in $d.HomedResources.HomedResource) { $found = 0 foreach ($c in $hr.Containers.Container) { foreach ($p in $c.Publication) { If ($p.CategoryName -eq 'contactCard' -and $p.InstanceNum -eq 6 -and $p.Data.contactCard.displayADPhoto -eq 'false') { If ($hr.UserAtHost -ne $lastProcessedUser) { "$($hr.UserAtHost) reset" $lastProcessedUser = $hr.UserAtHost } $p.Data.contactCard.displayADPhoto = 'true' $p.Version = (([int] $p.Version) + 1).ToString() $p.PrevPubTime = $p.LastPubTime $p.LastPubTime = (Get-Date -Format s).ToString() $found = 1 $changes++ } } } If ($found -eq 0) { [Void]$d.HomedResources.RemoveChild($hr) } } "Changes: $changes" If ($changes -ne 0) { "Saving XML..." $d.Save("$exportdir\Import-Pictures.xml") "Importing users..." $p = [diagnostics.process]::start('"C:\Program Files\Common Files\Microsoft Lync Server 2010\Support\DBImpExp.exe"', "/import /hrxmlfile:""$exportdir\Import-Pictures.xml"" /restype:user $sqlserver") $p.WaitForExit() } "Finished import, cleaning up..." If (Test-Path "$exportdir\Export-Pictures.xml") { Remove-Item "$exportdir\Export-Pictures.xml" } If (Test-Path "$exportdir\Import-Pictures.xml") { Remove-Item "$exportdir\Import-Pictures.xml" } "Done"
Hey Shannon / Guys
Just wanted to add frustration that users can still disable they picture which defeats the entire object of forcing it.
However, the script works great, so we just run it now every couple of hours for good measure.
Thanks for the script. Its much appreciated
Lets hope MS fix this in the next patch cycle!
Andy
Hey Shannon / Guys
Just wanted to add frustration that users can still disable they picture which defeats the entire object of forcing it.
However, the script works great, so we just run it now every couple of hours for good measure.
Thanks for the script. Its much appreciated
Lets hope MS fix this in the next patch cycle!
Andy
Just to add my 2p:
Same problem here. 3000+ users.
Same here. There are plans that within a few years the entire public sector of our devolved government will be in a single directory. That inlcudes health services, education services (both futher education, and higher eductation and schools), local government and councils, police forces, various QUANGOs. Literally hundreds of thousands of workers spread over 1000s of sites over more than 8000 square miles. We are having great sucess with the script above that we run every 5 mins, all day, every day but I am pretty sure that that kind of script/solution can't scale to something that large, or something in the cloud.
Good news however is there appears to be an inline policy to stop the user disabling the picture in Lync 2013!
Same issue. 2000+ users affected...
Backup and Test Before Use On a Production System - NOT Supported by Microsoft
This is a workaround for Lync 2013 (could be modified easily for 2010 as well)
The following powershell command will directly update the appropriate database record on each FrontEnd server of a given pool.
$domain = 'your domain name here'
(Get-CsPool (Get-CsComputer "$(hostname).$domain").Pool).Computers | % {
Invoke-Sqlcmd -Query "update rtc.dbo.PublishedStaticInstance Set Data = CONVERT(image,convert(varbinary(4000),REPLACE(convert(varchar(4000),convert(varbinary(4000),Data)),'<displayADPhoto>false</displayADPhoto>','<displayADPhoto>true</displayADPhoto>')))
where convert(varchar(4000),convert(varbinary(4000),Data)) like '%<displayADPhoto>false</displayADPhoto>%';" -ServerInstance "$($_)\RTCLOCAL"
}
Credit for SQL to: http://www.sipstories.com/2012/05/07/really-controlling-which-pictures-your-users-display-in-lync/
If someone knows how to initiate a sync between hosts for this table please let me know as it would be preferable to only connect to and update a single front end.
Backup and Test Before Use On a Production System - NOT Supported by Microsoft
This is a workaround for Lync 2013 (could be modified easily for 2010 as well)
The following powershell command will directly update the appropriate database record on each FrontEnd server of a given pool.
$domain = 'your domain name here'
(Get-CsPool (Get-CsComputer "$(hostname).$domain").Pool).Computers | % {
Invoke-Sqlcmd -Query "update rtc.dbo.PublishedStaticInstance Set Data = CONVERT(image,convert(varbinary(4000),REPLACE(convert(varchar(4000),convert(varbinary(4000),Data)),'<displayADPhoto>false</displayADPhoto>','<displayADPhoto>true</displayADPhoto>')))
where convert(varchar(4000),convert(varbinary(4000),Data)) like '%<displayADPhoto>false</displayADPhoto>%';" -ServerInstance "$($_)\RTCLOCAL"
}
Credit for SQL to: http://www.sipstories.com/2012/05/07/really-controlling-which-pictures-your-users-display-in-lync/
If someone knows how to initiate a sync between hosts for this table please let me know as it would be preferable to only connect to and update a single front end.
Backup and Test Before Use On a Production System - NOT Supported by Microsoft
This is a workaround for Lync 2013 (could be modified easily for 2010 as well)
The following powershell command will directly update the appropriate database record on each FrontEnd server of a given pool.
$domain = 'your domain name here'
(Get-CsPool (Get-CsComputer "$(hostname).$domain").Pool).Computers | % {
Invoke-Sqlcmd -Query "update rtc.dbo.PublishedStaticInstance Set Data = CONVERT(image,convert(varbinary(4000),REPLACE(convert(varchar(4000),convert(varbinary(4000),Data)),'<displayADPhoto>false</displayADPhoto>','<displayADPhoto>true</displayADPhoto>')))
where convert(varchar(4000),convert(varbinary(4000),Data)) like '%<displayADPhoto>false</displayADPhoto>%';" -ServerInstance "$($_)\RTCLOCAL"
}
Credit for SQL to: http://www.sipstories.com/2012/05/07/really-controlling-which-pictures-your-users-display-in-lync/
If someone knows how to initiate a sync between hosts for this table please let me know as it would be preferable to only connect to and update a single front end.
Backup and Test Before Use On a Production System - NOT Supported by Microsoft
This is a workaround for Lync 2013 (could be modified easily for 2010 as well)
The following powershell command will directly update the appropriate database record on each FrontEnd server of a given pool.
$domain = 'your domain name here'
(Get-CsPool (Get-CsComputer "$(hostname).$domain").Pool).Computers | % {
Invoke-Sqlcmd -Query "update rtc.dbo.PublishedStaticInstance Set Data = CONVERT(image,convert(varbinary(4000),REPLACE(convert(varchar(4000),convert(varbinary(4000),Data)),'<displayADPhoto>false</displayADPhoto>','<displayADPhoto>true</displayADPhoto>')))
where convert(varchar(4000),convert(varbinary(4000),Data)) like '%<displayADPhoto>false</displayADPhoto>%';" -ServerInstance "$($_)\RTCLOCAL"
}
Credit for SQL to: http://www.sipstories.com/2012/05/07/really-controlling-which-pictures-your-users-display-in-lync/
If someone knows how to initiate a sync between hosts for this table please let me know as it would be preferable to only connect to and update a single front end.
Backup and Test Before Use On a Production System - NOT Supported by Microsoft
This is a workaround for Lync 2013 (could be modified easily for 2010 as well)
The following powershell command will directly update the appropriate database record on each FrontEnd server of a given pool.
$domain = 'your domain name here'
(Get-CsPool (Get-CsComputer "$(hostname).$domain").Pool).Computers | % {
Invoke-Sqlcmd -Query "update rtc.dbo.PublishedStaticInstance Set Data = CONVERT(image,convert(varbinary(4000),REPLACE(convert(varchar(4000),convert(varbinary(4000),Data)),'<displayADPhoto>false</displayADPhoto>','<displayADPhoto>true</displayADPhoto>')))
where convert(varchar(4000),convert(varbinary(4000),Data)) like '%<displayADPhoto>false</displayADPhoto>%';" -ServerInstance "$($_)\RTCLOCAL"
}
Credit for SQL to: http://www.sipstories.com/2012/05/07/really-controlling-which-pictures-your-users-display-in-lync/
If someone knows how to initiate a sync between hosts for this table please let me know as it would be preferable to only connect to and update a single front end.
Backup and Test Before Use On a Production System - NOT Supported by Microsoft
This is a workaround for Lync 2013 (could be modified easily for 2010 as well)
The following powershell command will directly update the appropriate database record on each FrontEnd server of a given pool.
$domain = 'your domain name here'
(Get-CsPool (Get-CsComputer "$(hostname).$domain").Pool).Computers | % {
Invoke-Sqlcmd -Query "update rtc.dbo.PublishedStaticInstance Set Data = CONVERT(image,convert(varbinary(4000),REPLACE(convert(varchar(4000),convert(varbinary(4000),Data)),'<displayADPhoto>false</displayADPhoto>','<displayADPhoto>true</displayADPhoto>')))
where convert(varchar(4000),convert(varbinary(4000),Data)) like '%<displayADPhoto>false</displayADPhoto>%';" -ServerInstance "$($_)\RTCLOCAL"
}
Credit for SQL to: http://www.sipstories.com/2012/05/07/really-controlling-which-pictures-your-users-display-in-lync/
If someone knows how to initiate a sync between hosts for this table please let me know as it would be preferable to only connect to and update a single front end.
Hmm question as this likely makes a difference.
What type of deployment do you have? My script was being run against a Single Site Enterprise Deployment. Likely it might need alteration for Standard or for Multi-Site deployments.
Other than restarting my client I did not need to delete the profile.
The script as written was designed to run from one of the Front-End servers. If you running from an alternate host you'll need update some of the code to target one of your front-end servers.
"$(hostname).$domain"
changes to
"myfe1.domain.local' <== your fqdn for a front end here
If on a host other than a Front-End it very likely would run but not do anything.
Also of note I'm running in Powershell 3.0 (via Windows 2012), which may or may not be a factor. Powershell 3.0 can be installed on Windows 7 and Windows 2008r2 which should get you far enough for the script to work from that aspect.
I presume you running on an account with Local Admin rights to the Lync servers as well. The script is logging into the RTCLOCAL sql instances which run on the Front-Ends
Hmm question as this likely makes a difference.
What type of deployment do you have? My script was being run against a Single Site Enterprise Deployment. Likely it might need alteration for Standard or for Multi-Site deployments.
Other than restarting my client I did not need to delete the profile.
The script as written was designed to run from one of the Front-End servers. If you running from an alternate host you'll need update some of the code to target one of your front-end servers.
"$(hostname).$domain"
changes to
"myfe1.domain.local' <== your fqdn for a front end here
If on a host other than a Front-End it very likely would run but not do anything.
Also of note I'm running in Powershell 3.0 (via Windows 2012), which may or may not be a factor. Powershell 3.0 can be installed on Windows 7 and Windows 2008r2 which should get you far enough for the script to work from that aspect.
I presume you running on an account with Local Admin rights to the Lync servers as well. The script is logging into the RTCLOCAL sql instances which run on the Front-Ends
Hmm question as this likely makes a difference.
What type of deployment do you have? My script was being run against a Single Site Enterprise Deployment. Likely it might need alteration for Standard or for Multi-Site deployments.
Other than restarting my client I did not need to delete the profile.
The script as written was designed to run from one of the Front-End servers. If you running from an alternate host you'll need update some of the code to target one of your front-end servers.
"$(hostname).$domain"
changes to
"myfe1.domain.local' <== your fqdn for a front end here
If on a host other than a Front-End it very likely would run but not do anything.
Also of note I'm running in Powershell 3.0 (via Windows 2012), which may or may not be a factor. Powershell 3.0 can be installed on Windows 7 and Windows 2008r2 which should get you far enough for the script to work from that aspect.
I presume you running on an account with Local Admin rights to the Lync servers as well. The script is logging into the RTCLOCAL sql instances which run on the Front-Ends
Hmm question as this likely makes a difference.
What type of deployment do you have? My script was being run against a Single Site Enterprise Deployment. Likely it might need alteration for Standard or for Multi-Site deployments.
Other than restarting my client I did not need to delete the profile.
The script as written was designed to run from one of the Front-End servers. If you running from an alternate host you'll need update some of the code to target one of your front-end servers.
"$(hostname).$domain"
changes to
"myfe1.domain.local' <== your fqdn for a front end here
If on a host other than a Front-End it very likely would run but not do anything.
Also of note I'm running in Powershell 3.0 (via Windows 2012), which may or may not be a factor. Powershell 3.0 can be installed on Windows 7 and Windows 2008r2 which should get you far enough for the script to work from that aspect.
I presume you running on an account with Local Admin rights to the Lync servers as well. The script is logging into the RTCLOCAL sql instances which run on the Front-Ends
Hmm question as this likely makes a difference.
What type of deployment do you have? My script was being run against a Single Site Enterprise Deployment. Likely it might need alteration for Standard or for Multi-Site deployments.
Other than restarting my client I did not need to delete the profile.
The script as written was designed to run from one of the Front-End servers. If you running from an alternate host you'll need update some of the code to target one of your front-end servers.
"$(hostname).$domain"
changes to
"myfe1.domain.local' <== your fqdn for a front end here
If on a host other than a Front-End it very likely would run but not do anything.
Also of note I'm running in Powershell 3.0 (via Windows 2012), which may or may not be a factor. Powershell 3.0 can be installed on Windows 7 and Windows 2008r2 which should get you far enough for the script to work from that aspect.
I presume you running on an account with Local Admin rights to the Lync servers as well. The script is logging into the RTCLOCAL sql instances which run on the Front-Ends
Hi Michael,
I switched my user to No Picture in Lync, shut down my client, ran this in powershell on the FE server, deleted my SIP config profile off the client and restarted my Lync client. The setting was still set to No Picture. Im not really sure whats happening but it doesnt appear as its working. The script ran without error.
Hmm question as this likely makes a difference.
What type of deployment do you have? My script was being run against a Single Site Enterprise Deployment. Likely it might need alteration for Standard or for Multi-Site deployments.
Other than restarting my client I did not need to delete the profile.
The script as written was designed to run from one of the Front-End servers. If you running from an alternate host you'll need update some of the code to target one of your front-end servers.
"$(hostname).$domain"
changes to
"myfe1.domain.local' <== your fqdn for a front end here
If on a host other than a Front-End it very likely would run but not do anything.
Also of note I'm running in Powershell 3.0 (via Windows 2012), which may or may not be a factor. Powershell 3.0 can be installed on Windows 7 and Windows 2008r2 which should get you far enough for the script to work from that aspect.
I presume you running on an account with Local Admin rights to the Lync servers as well. The script is logging into the RTCLOCAL sql instances which run on the Front-Ends
Michael,
Your script is working flawlessly. Thank you. I verified it was working by logging onto the DB in SQL Studio and running the query....
select UserAtHost,convert(varchar(4000),convert(varbinary(4000),Data))
from PublishedStaticInstance,Resource
where ResourceId = PublisherId
and convert(varchar(4000),convert(varbinary(4000),Data))
like '%<displayADPhoto>%'
A before and after showed your script was changing the values as expected. I ran the Update-CsAddressBook command and now my client shows the AD picture selection again. I am not clear if that was required or if it was coincidence but the result is the same.
Thank you
Be careful running the Powershell script above!
6,000 concurrent users logged on; single site, 1 enterprise pool, 3 FE's, SQL 2008R2 backend.
As a test, i set my Lync config to "Do Not Show Picture", ran this script from a FE server. Dbimpexp.exe showed:
While "reindexing all tables and updating statistics" at least 1/3 (possibly more) of my user base saw the big ugly red banner message appear in their client, "Limited functionality is available due to outage" shown below.
At this point i'm still not sure what database(s) were reindexed. Were they the ones hosted on the SQL cluster backend? Or was it the the local db hosted on the FE where my SIP account is registered? Searched the inet high and low trying to find an answer but couldn't.
Good news: as written above, the script works perfectly. My setting was forced back to showing the default corporate picture after signing out then back in.
Bad news: Can cause an outage. Use at your own risk and definitely run it at off peak hours.
Be careful running the Powershell script above!
6,000 concurrent users logged on; single site, 1 enterprise pool, 3 FE's, SQL 2008R2 backend.
As a test, i set my Lync config to "Do Not Show Picture", ran this script from a FE server. Dbimpexp.exe showed:
While "reindexing all tables and updating statistics" at least 1/3 (possibly more) of my user base saw the big ugly red banner message appear in their client, "Limited functionality is available due to outage" shown below.
At this point i'm still not sure what database(s) were reindexed. Were they the ones hosted on the SQL cluster backend? Or was it the the local db hosted on the FE where my SIP account is registered? Searched the inet high and low trying to find an answer but couldn't.
Good news: as written above, the script works perfectly. My setting was forced back to showing the default corporate picture after signing out then back in.
Bad news: Can cause an outage. Use at your own risk and definitely run it at off peak hours.
Be careful running the Powershell script above!
6,000 concurrent users logged on; single site, 1 enterprise pool, 3 FE's, SQL 2008R2 backend.
As a test, i set my Lync config to "Do Not Show Picture", ran this script from a FE server. Dbimpexp.exe showed:
While "reindexing all tables and updating statistics" at least 1/3 (possibly more) of my user base saw the big ugly red banner message appear in their client, "Limited functionality is available due to outage" shown below.
At this point i'm still not sure what database(s) were reindexed. Were they the ones hosted on the SQL cluster backend? Or was it the the local db hosted on the FE where my SIP account is registered? Searched the inet high and low trying to find an answer but couldn't.
Good news: as written above, the script works perfectly. My setting was forced back to showing the default corporate picture after signing out then back in.
Bad news: Can cause an outage. Use at your own risk and definitely run it at off peak hours.
Be careful running the Powershell script above!
6,000 concurrent users logged on; single site, 1 enterprise pool, 3 FE's, SQL 2008R2 backend.
As a test, i set my Lync config to "Do Not Show Picture", ran this script from a FE server. Dbimpexp.exe showed:
While "reindexing all tables and updating statistics" at least 1/3 (possibly more) of my user base saw the big ugly red banner message appear in their client, "Limited functionality is available due to outage" shown below.
At this point i'm still not sure what database(s) were reindexed. Were they the ones hosted on the SQL cluster backend? Or was it the the local db hosted on the FE where my SIP account is registered? Searched the inet high and low trying to find an answer but couldn't.
Good news: as written above, the script works perfectly. My setting was forced back to showing the default corporate picture after signing out then back in.
Bad news: Can cause an outage. Use at your own risk and definitely run it at off peak hours.
Be careful running the Powershell script above!
6,000 concurrent users logged on; single site, 1 enterprise pool, 3 FE's, SQL 2008R2 backend.
As a test, i set my Lync config to "Do Not Show Picture", ran this script from a FE server. Dbimpexp.exe showed:
While "reindexing all tables and updating statistics" at least 1/3 (possibly more) of my user base saw the big ugly red banner message appear in their client, "Limited functionality is available due to outage" shown below.
At this point i'm still not sure what database(s) were reindexed. Were they the ones hosted on the SQL cluster backend? Or was it the the local db hosted on the FE where my SIP account is registered? Searched the inet high and low trying to find an answer but couldn't.
Good news: as written above, the script works perfectly. My setting was forced back to showing the default corporate picture after signing out then back in.
Bad news: Can cause an outage. Use at your own risk and definitely run it at off peak hours.
Be careful running the Powershell script above!
6,000 concurrent users logged on; single site, 1 enterprise pool, 3 FE's, SQL 2008R2 backend.
As a test, i set my Lync config to "Do Not Show Picture", ran this script from a FE server. Dbimpexp.exe showed:
While "reindexing all tables and updating statistics" at least 1/3 (possibly more) of my user base saw the big ugly red banner message appear in their client, "Limited functionality is available due to outage" shown below.
At this point i'm still not sure what database(s) were reindexed. Were they the ones hosted on the SQL cluster backend? Or was it the the local db hosted on the FE where my SIP account is registered? Searched the inet high and low trying to find an answer but couldn't.
Good news: as written above, the script works perfectly. My setting was forced back to showing the default corporate picture after signing out then back in.
Bad news: Can cause an outage. Use at your own risk and definitely run it at off peak hours.
Indeed! Because Microsoft decided to store this data (incorrectly) in an image field it means that we have to extract the data on every record every time the script runs. That is a fairly intensive operation despite that data size being low. Image fields can not be indexed so you have to scan ALL of the records. I have over 1400 users in my database and it shows 100k records in that table takes about 2 seconds to complete running on a VM.
This might help (a lot):
Add a filter on [LastPubTime]
Assume you run the script once every 15 minutes you'd set the offset value to 15 minutes or if you want an overlap 20 minutes.
function Enable-UserPhotos ($Domain, $OffSet) {
(Get-CsPool (Get-CsComputer "$(hostname).$Domain").Pool).Computers | % {
Invoke-Sqlcmd -Query "update rtc.dbo.PublishedStaticInstance Set Data = CONVERT(image,convert(varbinary(4000),REPLACE(convert(varchar(4000),convert(varbinary(4000),Data)),'<displayADPhoto>false</displayADPhoto>','<displayADPhoto>true</displayADPhoto>')))
where [LastPubTime] >= DATEADD(mi,-$($OffSet),getdate()) AND convert(varchar(4000),convert(varbinary(4000),Data)) like '%<displayADPhoto>false</displayADPhoto>%';" -ServerInstance "$($_)\RTCLOCAL"
}
}
Enable-UserPhotos -Domain 'your domain name here' -OffSet 15
Adding this filter should carve off a significant portion of the execution time of your query time per front end. Why? Because you'll only be checking the records that have changed within the Offset period that you specify. Even in an environment with 10k+ users your likely only looking at a very relatively small row set within that timeframe (relative to a full table scan). The more frequent the script runs the lower the time taken (to a point) I would not run this more often than every 5 minutes and recommend 15 - 60 minutes.. Mileage will very but I would not exceed 24 hours between for larger environment as the more users the longer time between the more potential records to parse.
The above WILL greatly reduce the chance of an outage due to index locks as seen by J.Kuta
Additionally disk performance will play in to this for large implementations the default location of these databases is C drive. More than likely you running either single spindle or a mirrored pair (same speed as a single). Moving these databases to a striped raid or raid5/6/10 will help desk performance. Memory too plays a big part in this.
Two things I typically do to every SQL server I touch:
Check the Memory allocation
Override 'Cost Threshold for Parellelism' (Advanced Tab for the sql instance) to a value of 0
Memory is kind of a duh, the more memory the more data is held in memory. Lync tries to auto calculate based on available memory so that it doesn't fight with IIS. I recommend at least 4GB or larger for even a small system, adjust as makes sense.
'Cost Threshold for Parallelism' I had a conversation with one the of the lead guys at Microsoft one day at a dynamics user conference and ask about this. Essentially this setting mostly a relic of the single core days of processors. Setting 0 makes SQL always consider using multiple threads and thus cpu. I typically see systems running at sustained 30-60% cpu utilization, drop in to the teens to single digits. SQL understands parallel processing, let it do its thing. Memory and disk plays in to this as well, simultaneous processes will use more memory. Faster processing will hit the disk harder as it can consume it faster.
Indeed! Because Microsoft decided to store this data (incorrectly) in an image field it means that we have to extract the data on every record every time the script runs. That is a fairly intensive operation despite that data size being low. Image fields can not be indexed so you have to scan ALL of the records. I have over 1400 users in my database and it shows 100k records in that table takes about 2 seconds to complete running on a VM.
This might help (a lot):
Add a filter on [LastPubTime]
Assume you run the script once every 15 minutes you'd set the offset value to 15 minutes or if you want an overlap 20 minutes.
function Enable-UserPhotos ($Domain, $OffSet) {
(Get-CsPool (Get-CsComputer "$(hostname).$Domain").Pool).Computers | % {
Invoke-Sqlcmd -Query "update rtc.dbo.PublishedStaticInstance Set Data = CONVERT(image,convert(varbinary(4000),REPLACE(convert(varchar(4000),convert(varbinary(4000),Data)),'<displayADPhoto>false</displayADPhoto>','<displayADPhoto>true</displayADPhoto>')))
where [LastPubTime] >= DATEADD(mi,-$($OffSet),getdate()) AND convert(varchar(4000),convert(varbinary(4000),Data)) like '%<displayADPhoto>false</displayADPhoto>%';" -ServerInstance "$($_)\RTCLOCAL"
}
}
Enable-UserPhotos -Domain 'your domain name here' -OffSet 15
Adding this filter should carve off a significant portion of the execution time of your query time per front end. Why? Because you'll only be checking the records that have changed within the Offset period that you specify. Even in an environment with 10k+ users your likely only looking at a very relatively small row set within that timeframe (relative to a full table scan). The more frequent the script runs the lower the time taken (to a point) I would not run this more often than every 5 minutes and recommend 15 - 60 minutes.. Mileage will very but I would not exceed 24 hours between for larger environment as the more users the longer time between the more potential records to parse.
The above WILL greatly reduce the chance of an outage due to index locks as seen by J.Kuta
Additionally disk performance will play in to this for large implementations the default location of these databases is C drive. More than likely you running either single spindle or a mirrored pair (same speed as a single). Moving these databases to a striped raid or raid5/6/10 will help desk performance. Memory too plays a big part in this.
Two things I typically do to every SQL server I touch:
Check the Memory allocation
Override 'Cost Threshold for Parellelism' (Advanced Tab for the sql instance) to a value of 0
Memory is kind of a duh, the more memory the more data is held in memory. Lync tries to auto calculate based on available memory so that it doesn't fight with IIS. I recommend at least 4GB or larger for even a small system, adjust as makes sense.
'Cost Threshold for Parallelism' I had a conversation with one the of the lead guys at Microsoft one day at a dynamics user conference and ask about this. Essentially this setting mostly a relic of the single core days of processors. Setting 0 makes SQL always consider using multiple threads and thus cpu. I typically see systems running at sustained 30-60% cpu utilization, drop in to the teens to single digits. SQL understands parallel processing, let it do its thing. Memory and disk plays in to this as well, simultaneous processes will use more memory. Faster processing will hit the disk harder as it can consume it faster.
Indeed! Because Microsoft decided to store this data (incorrectly) in an image field it means that we have to extract the data on every record every time the script runs. That is a fairly intensive operation despite that data size being low. Image fields can not be indexed so you have to scan ALL of the records. I have over 1400 users in my database and it shows 100k records in that table takes about 2 seconds to complete running on a VM.
This might help (a lot):
Add a filter on [LastPubTime]
Assume you run the script once every 15 minutes you'd set the offset value to 15 minutes or if you want an overlap 20 minutes.
function Enable-UserPhotos ($Domain, $OffSet) {
(Get-CsPool (Get-CsComputer "$(hostname).$Domain").Pool).Computers | % {
Invoke-Sqlcmd -Query "update rtc.dbo.PublishedStaticInstance Set Data = CONVERT(image,convert(varbinary(4000),REPLACE(convert(varchar(4000),convert(varbinary(4000),Data)),'<displayADPhoto>false</displayADPhoto>','<displayADPhoto>true</displayADPhoto>')))
where [LastPubTime] >= DATEADD(mi,-$($OffSet),getdate()) AND convert(varchar(4000),convert(varbinary(4000),Data)) like '%<displayADPhoto>false</displayADPhoto>%';" -ServerInstance "$($_)\RTCLOCAL"
}
}
Enable-UserPhotos -Domain 'your domain name here' -OffSet 15
Adding this filter should carve off a significant portion of the execution time of your query time per front end. Why? Because you'll only be checking the records that have changed within the Offset period that you specify. Even in an environment with 10k+ users your likely only looking at a very relatively small row set within that timeframe (relative to a full table scan). The more frequent the script runs the lower the time taken (to a point) I would not run this more often than every 5 minutes and recommend 15 - 60 minutes.. Mileage will very but I would not exceed 24 hours between for larger environment as the more users the longer time between the more potential records to parse.
The above WILL greatly reduce the chance of an outage due to index locks as seen by J.Kuta
Additionally disk performance will play in to this for large implementations the default location of these databases is C drive. More than likely you running either single spindle or a mirrored pair (same speed as a single). Moving these databases to a striped raid or raid5/6/10 will help desk performance. Memory too plays a big part in this.
Two things I typically do to every SQL server I touch:
Check the Memory allocation
Override 'Cost Threshold for Parellelism' (Advanced Tab for the sql instance) to a value of 0
Memory is kind of a duh, the more memory the more data is held in memory. Lync tries to auto calculate based on available memory so that it doesn't fight with IIS. I recommend at least 4GB or larger for even a small system, adjust as makes sense.
'Cost Threshold for Parallelism' I had a conversation with one the of the lead guys at Microsoft one day at a dynamics user conference and ask about this. Essentially this setting mostly a relic of the single core days of processors. Setting 0 makes SQL always consider using multiple threads and thus cpu. I typically see systems running at sustained 30-60% cpu utilization, drop in to the teens to single digits. SQL understands parallel processing, let it do its thing. Memory and disk plays in to this as well, simultaneous processes will use more memory. Faster processing will hit the disk harder as it can consume it faster.
Indeed! Because Microsoft decided to store this data (incorrectly) in an image field it means that we have to extract the data on every record every time the script runs. That is a fairly intensive operation despite that data size being low. Image fields can not be indexed so you have to scan ALL of the records. I have over 1400 users in my database and it shows 100k records in that table takes about 2 seconds to complete running on a VM.
This might help (a lot):
Add a filter on [LastPubTime]
Assume you run the script once every 15 minutes you'd set the offset value to 15 minutes or if you want an overlap 20 minutes.
function Enable-UserPhotos ($Domain, $OffSet) {
(Get-CsPool (Get-CsComputer "$(hostname).$Domain").Pool).Computers | % {
Invoke-Sqlcmd -Query "update rtc.dbo.PublishedStaticInstance Set Data = CONVERT(image,convert(varbinary(4000),REPLACE(convert(varchar(4000),convert(varbinary(4000),Data)),'<displayADPhoto>false</displayADPhoto>','<displayADPhoto>true</displayADPhoto>')))
where [LastPubTime] >= DATEADD(mi,-$($OffSet),getdate()) AND convert(varchar(4000),convert(varbinary(4000),Data)) like '%<displayADPhoto>false</displayADPhoto>%';" -ServerInstance "$($_)\RTCLOCAL"
}
}
Enable-UserPhotos -Domain 'your domain name here' -OffSet 15
Adding this filter should carve off a significant portion of the execution time of your query time per front end. Why? Because you'll only be checking the records that have changed within the Offset period that you specify. Even in an environment with 10k+ users your likely only looking at a very relatively small row set within that timeframe (relative to a full table scan). The more frequent the script runs the lower the time taken (to a point) I would not run this more often than every 5 minutes and recommend 15 - 60 minutes.. Mileage will very but I would not exceed 24 hours between for larger environment as the more users the longer time between the more potential records to parse.
The above WILL greatly reduce the chance of an outage due to index locks as seen by J.Kuta
Additionally disk performance will play in to this for large implementations the default location of these databases is C drive. More than likely you running either single spindle or a mirrored pair (same speed as a single). Moving these databases to a striped raid or raid5/6/10 will help desk performance. Memory too plays a big part in this.
Two things I typically do to every SQL server I touch:
Check the Memory allocation
Override 'Cost Threshold for Parellelism' (Advanced Tab for the sql instance) to a value of 0
Memory is kind of a duh, the more memory the more data is held in memory. Lync tries to auto calculate based on available memory so that it doesn't fight with IIS. I recommend at least 4GB or larger for even a small system, adjust as makes sense.
'Cost Threshold for Parallelism' I had a conversation with one the of the lead guys at Microsoft one day at a dynamics user conference and ask about this. Essentially this setting mostly a relic of the single core days of processors. Setting 0 makes SQL always consider using multiple threads and thus cpu. I typically see systems running at sustained 30-60% cpu utilization, drop in to the teens to single digits. SQL understands parallel processing, let it do its thing. Memory and disk plays in to this as well, simultaneous processes will use more memory. Faster processing will hit the disk harder as it can consume it faster.
Indeed! Because Microsoft decided to store this data (incorrectly) in an image field it means that we have to extract the data on every record every time the script runs. That is a fairly intensive operation despite that data size being low. Image fields can not be indexed so you have to scan ALL of the records. I have over 1400 users in my database and it shows 100k records in that table takes about 2 seconds to complete running on a VM.
This might help (a lot):
Add a filter on [LastPubTime]
Assume you run the script once every 15 minutes you'd set the offset value to 15 minutes or if you want an overlap 20 minutes.
function Enable-UserPhotos ($Domain, $OffSet) {
(Get-CsPool (Get-CsComputer "$(hostname).$Domain").Pool).Computers | % {
Invoke-Sqlcmd -Query "update rtc.dbo.PublishedStaticInstance Set Data = CONVERT(image,convert(varbinary(4000),REPLACE(convert(varchar(4000),convert(varbinary(4000),Data)),'<displayADPhoto>false</displayADPhoto>','<displayADPhoto>true</displayADPhoto>')))
where [LastPubTime] >= DATEADD(mi,-$($OffSet),getdate()) AND convert(varchar(4000),convert(varbinary(4000),Data)) like '%<displayADPhoto>false</displayADPhoto>%';" -ServerInstance "$($_)\RTCLOCAL"
}
}
Enable-UserPhotos -Domain 'your domain name here' -OffSet 15
Adding this filter should carve off a significant portion of the execution time of your query time per front end. Why? Because you'll only be checking the records that have changed within the Offset period that you specify. Even in an environment with 10k+ users your likely only looking at a very relatively small row set within that timeframe (relative to a full table scan). The more frequent the script runs the lower the time taken (to a point) I would not run this more often than every 5 minutes and recommend 15 - 60 minutes.. Mileage will very but I would not exceed 24 hours between for larger environment as the more users the longer time between the more potential records to parse.
The above WILL greatly reduce the chance of an outage due to index locks as seen by J.Kuta
Additionally disk performance will play in to this for large implementations the default location of these databases is C drive. More than likely you running either single spindle or a mirrored pair (same speed as a single). Moving these databases to a striped raid or raid5/6/10 will help desk performance. Memory too plays a big part in this.
Two things I typically do to every SQL server I touch:
Check the Memory allocation
Override 'Cost Threshold for Parellelism' (Advanced Tab for the sql instance) to a value of 0
Memory is kind of a duh, the more memory the more data is held in memory. Lync tries to auto calculate based on available memory so that it doesn't fight with IIS. I recommend at least 4GB or larger for even a small system, adjust as makes sense.
'Cost Threshold for Parallelism' I had a conversation with one the of the lead guys at Microsoft one day at a dynamics user conference and ask about this. Essentially this setting mostly a relic of the single core days of processors. Setting 0 makes SQL always consider using multiple threads and thus cpu. I typically see systems running at sustained 30-60% cpu utilization, drop in to the teens to single digits. SQL understands parallel processing, let it do its thing. Memory and disk plays in to this as well, simultaneous processes will use more memory. Faster processing will hit the disk harder as it can consume it faster.
Indeed! Because Microsoft decided to store this data (incorrectly) in an image field it means that we have to extract the data on every record every time the script runs. That is a fairly intensive operation despite that data size being low. Image fields can not be indexed so you have to scan ALL of the records. I have over 1400 users in my database and it shows 100k records in that table takes about 2 seconds to complete running on a VM.
This might help (a lot):
Add a filter on [LastPubTime]
Assume you run the script once every 15 minutes you'd set the offset value to 15 minutes or if you want an overlap 20 minutes.
function Enable-UserPhotos ($Domain, $OffSet) {
(Get-CsPool (Get-CsComputer "$(hostname).$Domain").Pool).Computers | % {
Invoke-Sqlcmd -Query "update rtc.dbo.PublishedStaticInstance Set Data = CONVERT(image,convert(varbinary(4000),REPLACE(convert(varchar(4000),convert(varbinary(4000),Data)),'<displayADPhoto>false</displayADPhoto>','<displayADPhoto>true</displayADPhoto>')))
where [LastPubTime] >= DATEADD(mi,-$($OffSet),getdate()) AND convert(varchar(4000),convert(varbinary(4000),Data)) like '%<displayADPhoto>false</displayADPhoto>%';" -ServerInstance "$($_)\RTCLOCAL"
}
}
Enable-UserPhotos -Domain 'your domain name here' -OffSet 15
Adding this filter should carve off a significant portion of the execution time of your query time per front end. Why? Because you'll only be checking the records that have changed within the Offset period that you specify. Even in an environment with 10k+ users your likely only looking at a very relatively small row set within that timeframe (relative to a full table scan). The more frequent the script runs the lower the time taken (to a point) I would not run this more often than every 5 minutes and recommend 15 - 60 minutes.. Mileage will very but I would not exceed 24 hours between for larger environment as the more users the longer time between the more potential records to parse.
The above WILL greatly reduce the chance of an outage due to index locks as seen by J.Kuta
Additionally disk performance will play in to this for large implementations the default location of these databases is C drive. More than likely you running either single spindle or a mirrored pair (same speed as a single). Moving these databases to a striped raid or raid5/6/10 will help desk performance. Memory too plays a big part in this.
Two things I typically do to every SQL server I touch:
Check the Memory allocation
Override 'Cost Threshold for Parellelism' (Advanced Tab for the sql instance) to a value of 0
Memory is kind of a duh, the more memory the more data is held in memory. Lync tries to auto calculate based on available memory so that it doesn't fight with IIS. I recommend at least 4GB or larger for even a small system, adjust as makes sense.
'Cost Threshold for Parallelism' I had a conversation with one the of the lead guys at Microsoft one day at a dynamics user conference and ask about this. Essentially this setting mostly a relic of the single core days of processors. Setting 0 makes SQL always consider using multiple threads and thus cpu. I typically see systems running at sustained 30-60% cpu utilization, drop in to the teens to single digits. SQL understands parallel processing, let it do its thing. Memory and disk plays in to this as well, simultaneous processes will use more memory. Faster processing will hit the disk harder as it can consume it faster.
At this point i'm still not sure what database(s) were reindexed. Were they the ones hosted on the SQL cluster backend? Or was it the the local db hosted on the FE where my SIP account is
I'm assuming you ran 'Display Estimate Execution Plan'?
Keep in mind that this is cost not time which does not always an indicator of time. The real bulk of execution time is the 'Compute Scalar' as that's where the image conversion is occurring (I believe)
To more directly answer however the update occurs directly on each frontend in the LOCALRTC sql instance. So if one server takes 10 minutes and you have 15.. you'll be there a while. My previous post however should greatly reduce that time, hopefully to seconds in most cases.
At this point i'm still not sure what database(s) were reindexed. Were they the ones hosted on the SQL cluster backend? Or was it the the local db hosted on the FE where my SIP account is
I'm assuming you ran 'Display Estimate Execution Plan'?
Keep in mind that this is cost not time which does not always an indicator of time. The real bulk of execution time is the 'Compute Scalar' as that's where the image conversion is occurring (I believe)
To more directly answer however the update occurs directly on each frontend in the LOCALRTC sql instance. So if one server takes 10 minutes and you have 15.. you'll be there a while. My previous post however should greatly reduce that time, hopefully to seconds in most cases.
At this point i'm still not sure what database(s) were reindexed. Were they the ones hosted on the SQL cluster backend? Or was it the the local db hosted on the FE where my SIP account is
I'm assuming you ran 'Display Estimate Execution Plan'?
Keep in mind that this is cost not time which does not always an indicator of time. The real bulk of execution time is the 'Compute Scalar' as that's where the image conversion is occurring (I believe)
To more directly answer however the update occurs directly on each frontend in the LOCALRTC sql instance. So if one server takes 10 minutes and you have 15.. you'll be there a while. My previous post however should greatly reduce that time, hopefully to seconds in most cases.
At this point i'm still not sure what database(s) were reindexed. Were they the ones hosted on the SQL cluster backend? Or was it the the local db hosted on the FE where my SIP account is
I'm assuming you ran 'Display Estimate Execution Plan'?
Keep in mind that this is cost not time which does not always an indicator of time. The real bulk of execution time is the 'Compute Scalar' as that's where the image conversion is occurring (I believe)
To more directly answer however the update occurs directly on each frontend in the LOCALRTC sql instance. So if one server takes 10 minutes and you have 15.. you'll be there a while. My previous post however should greatly reduce that time, hopefully to seconds in most cases.
At this point i'm still not sure what database(s) were reindexed. Were they the ones hosted on the SQL cluster backend? Or was it the the local db hosted on the FE where my SIP account is
I'm assuming you ran 'Display Estimate Execution Plan'?
Keep in mind that this is cost not time which does not always an indicator of time. The real bulk of execution time is the 'Compute Scalar' as that's where the image conversion is occurring (I believe)
To more directly answer however the update occurs directly on each frontend in the LOCALRTC sql instance. So if one server takes 10 minutes and you have 15.. you'll be there a while. My previous post however should greatly reduce that time, hopefully to seconds in most cases.
At this point i'm still not sure what database(s) were reindexed. Were they the ones hosted on the SQL cluster backend? Or was it the the local db hosted on the FE where my SIP account is
I'm assuming you ran 'Display Estimate Execution Plan'?
Keep in mind that this is cost not time which does not always an indicator of time. The real bulk of execution time is the 'Compute Scalar' as that's where the image conversion is occurring (I believe)
To more directly answer however the update occurs directly on each frontend in the LOCALRTC sql instance. So if one server takes 10 minutes and you have 15.. you'll be there a while. My previous post however should greatly reduce that time, hopefully to seconds in most cases.
Michael - thank you for your hard work on creating this script. I've implemented it in our environment, and found that the SQL query in your code block has an error due to syntax. Unless corrections below are made, the powershell script will run (without error) but will fail to modify the database because it passes an invalid SQL query. Here is the correction needed in your script block:
# Incorrect SQL query implementation [LastPubTime] >= DATEADD(mi,-$($OffSet),getdate()) # Correct SQL query implementation [LastPubTime] >= DATEADD(mi,-($OffSet),getdate())
Once the change is made, everything works perfectly well, and accomplishes the job.
Couldn't have done it without your hard work, and just wanted to save other users of this method some troubleshooting time.
Best,
Ilya
Michael - thank you for your hard work on creating this script. I've implemented it in our environment, and found that the SQL query in your code block has an error due to syntax. Unless corrections below are made, the powershell script will run (without error) but will fail to modify the database because it passes an invalid SQL query. Here is the correction needed in your script block:
# Incorrect SQL query implementation [LastPubTime] >= DATEADD(mi,-$($OffSet),getdate()) # Correct SQL query implementation [LastPubTime] >= DATEADD(mi,-($OffSet),getdate())
Once the change is made, everything works perfectly well, and accomplishes the job.
Couldn't have done it without your hard work, and just wanted to save other users of this method some troubleshooting time.
Best,
Ilya
Michael - thank you for your hard work on creating this script. I've implemented it in our environment, and found that the SQL query in your code block has an error due to syntax. Unless corrections below are made, the powershell script will run (without error) but will fail to modify the database because it passes an invalid SQL query. Here is the correction needed in your script block:
# Incorrect SQL query implementation [LastPubTime] >= DATEADD(mi,-$($OffSet),getdate()) # Correct SQL query implementation [LastPubTime] >= DATEADD(mi,-($OffSet),getdate())
Once the change is made, everything works perfectly well, and accomplishes the job.
Couldn't have done it without your hard work, and just wanted to save other users of this method some troubleshooting time.
Best,
Ilya
Michael - thank you for your hard work on creating this script. I've implemented it in our environment, and found that the SQL query in your code block has an error due to syntax. Unless corrections below are made, the powershell script will run (without error) but will fail to modify the database because it passes an invalid SQL query. Here is the correction needed in your script block:
# Incorrect SQL query implementation [LastPubTime] >= DATEADD(mi,-$($OffSet),getdate()) # Correct SQL query implementation [LastPubTime] >= DATEADD(mi,-($OffSet),getdate())
Once the change is made, everything works perfectly well, and accomplishes the job.
Couldn't have done it without your hard work, and just wanted to save other users of this method some troubleshooting time.
Best,
Ilya
Michael - thank you for your hard work on creating this script. I've implemented it in our environment, and found that the SQL query in your code block has an error due to syntax. Unless corrections below are made, the powershell script will run (without error) but will fail to modify the database because it passes an invalid SQL query. Here is the correction needed in your script block:
# Incorrect SQL query implementation [LastPubTime] >= DATEADD(mi,-$($OffSet),getdate()) # Correct SQL query implementation [LastPubTime] >= DATEADD(mi,-($OffSet),getdate())
Once the change is made, everything works perfectly well, and accomplishes the job.
Couldn't have done it without your hard work, and just wanted to save other users of this method some troubleshooting time.
Best,
Ilya
Michael - thank you for your hard work on creating this script. I've implemented it in our environment, and found that the SQL query in your code block has an error due to syntax. Unless corrections below are made, the powershell script will run (without error) but will fail to modify the database because it passes an invalid SQL query. Here is the correction needed in your script block:
# Incorrect SQL query implementation [LastPubTime] >= DATEADD(mi,-$($OffSet),getdate()) # Correct SQL query implementation [LastPubTime] >= DATEADD(mi,-($OffSet),getdate())
Once the change is made, everything works perfectly well, and accomplishes the job.
Couldn't have done it without your hard work, and just wanted to save other users of this method some troubleshooting time.
Best,
Ilya
Interesting may be a powershell version difference, what version of Powershell and what OS if I might ask? That said removing the $ should work for PS 1.0 through 3.0 just as well.
-$($OffSet) vs ,-($OffSet)
All that $() adds is a wrapper in powershell at the point it gets to SQL, assuming $OffSet = 15, it would look like -15. Wrapping in $() is normally used for more complex string inclusion, such as:
$Prefer = "blue"
$MyString = "My favorite color is $(if ($Prefer -ne $null) { $Prefer } else { "Purple" } ) but I like hot pink too"
The environment is Lync 2013 (Front Ends on Win2k8 R2 Enterprise servers), and SQL databases colocated on the same. Lync 2013 requires Powershell 3 to be installed, so that is what I was working with in terms of versioning.
To find why the script wasn't working, I had to run the SQL query from the script manually from SQL Studio against the Lync database, and then checked why powershell wasn't piping the variable correctly. When you include the $() wrapper, it breaks the query, and if you just pipe the variable in as ($OffSet) it works like a charm.
Again, thanks for your efforts - I can't believe Microsoft doesn't include this as a configurable option out of the box, and we have to hack it this way.
Whatever gets the job done!
Solution present in this thread!!!!
It is work!!
Do not answer it again if you do not know the right answer!
Minor Tweak for those who are executing from a machine other than a front end.
Note you need Lync powershell on the host still
function Enforce-UserPhotos ($Domain, $OffSet) {
130 users here that would really like the option. Hard to believe it's not in Group Policy or the Lync Policy settings especially for such a app that is a completely "corporate" focused.
I had to do the Powershell command with a scheduled task as shown in the previous messages which works ok except it's messy.
Another beef is the way Microsoft stores the Lync settings in the SQL database. I have been searching for the table that shows the Voice Dial Plan configuration for a while now...
Functionality is unchanged in Lync 2013, this thread covers both 2010 and 2013 implementations of this workaround.
I didn't find this to be true. I did however come up with a proven work-around. Please feel free to review, try it out, and leave feedback afterwards everyone. This is free, not a sales pitch :)
I'm shocked by the amount of people here who feel the need to force users to do something, as if they are incapable of making decisions for themselves. Obviously, your users don't want to show their photos, but somehow, you feel like it's the end of the world if they don't have it. The reply about it being a security risk is laughable. If a user photo in lync is part of your security framework, then your security system is terrible.
Instead of trying to tyrannically force the world to your view, how about listening to your users and realizing that forcing them to show photos is a terrible idea? Give them the choice.
I'm glad that you're in an environment where you have the luxury/ability to allow the users to choose. However, when the CEO has mandated that all users will have their picture displayed in Windows/Outlook/Lync, etc., giving the user the choice is not an option. Allowing the administrator to force that would make it much easier and a time-saver not having to 'police' it and/or always having to run a script to as a workaround.
Same Issue. 2,000 + Users
We need to stop our users from clicking "Hide my Photo".
We've been able to stop this on exchange and sharepoint, just not here.
I never cease to be amused at how crappy Microsoft is at listening to its customers...
Just for general awareness, can any of you please explain your business case for not allowing users to not display photos.
I personally do not find any significant value add to having a contact's photo displayed.
Here's a couple of reasons why it's important photos are displayed:
- New employees: it helps with name/face recognition when they are getting acclimated
- Receptionist: The receptionist can pull up a group conversation and see everyone's status and can quickly identify them by their picture to see if they are available or not. If the picture is hidden they have to hover over the person to see who it is.
Can anybody confirm whether this functionality has been added in Skype for business server? I'm guessing not, but there's at least hope.